/*
 *  Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
 *  <p>
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *  <p>
 *  http://www.apache.org/licenses/LICENSE-2.0
 *  <p>
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.gitee.fastmybatis.core.update;

import org.apache.ibatis.javassist.util.proxy.ProxyFactory;
import org.apache.ibatis.javassist.util.proxy.ProxyObject;
import org.apache.ibatis.logging.LogFactory;

import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap;


public class ModifyAttrsRecordProxyFactory {

    private static final ModifyAttrsRecordProxyFactory instance = new ModifyAttrsRecordProxyFactory();

    public static ModifyAttrsRecordProxyFactory getInstance() {
        return instance;
    }

    private ModifyAttrsRecordProxyFactory() {
    }


    /**
     * srcClass -> proxyClass
     */
    private static ConcurrentHashMap<Class<?>, Class<?>> srcProxyMap = new ConcurrentHashMap<>();

    /**
     * proxyClass-> srcClass
     */
    private static ConcurrentHashMap<Class<?>, Class<?>> proxySrcMap = new ConcurrentHashMap<>();

    public static Class<?> getProxyClass(Class<?> src) {
        return srcProxyMap.get(src);
    }

    public static Class<?> getSrcClass(Class<?> proxy) {
        return proxySrcMap.get(proxy);
    }

    private Class<?> createProxyClass(Class<?> target) {
        Class<?> proxyClass = srcProxyMap.get(target);
        if (null == proxyClass) {
            synchronized (ModifyAttrsRecordProxyFactory.class) {
                proxyClass = srcProxyMap.get(target);
                if (null == proxyClass) {
                    ProxyFactory factory = new ProxyFactory();
                    factory.setSuperclass(target);

                    Class<?>[] interfaces = Arrays.copyOf(target.getInterfaces(), target.getInterfaces().length + 1);
                    interfaces[interfaces.length - 1] = UpdateWrapper.class;
                    factory.setInterfaces(interfaces);

                    proxyClass = factory.createClass();
                    srcProxyMap.put(target, proxyClass);
                    proxySrcMap.put(proxyClass, target);

                    return proxyClass;
                }
            }
        }


        return proxyClass;


    }


    public synchronized <T> T get(Class<T> target) {

        Class<?> proxyClass = createProxyClass(target);

        T proxyObject = null;
        try {
            proxyObject = (T) proxyClass.newInstance();
            ((ProxyObject) proxyObject).setHandler(new ModifyAttrsRecordHandler());
        } catch (Throwable e) {
            LogFactory.getLog(ModifyAttrsRecordProxyFactory.class).error(e.toString(), e);
        }

        return proxyObject;
    }


}



